package com.chuangke.mds.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.chuangke.admin.entity.SysUser;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chuangke.common.constant.ColumnConstants;
import com.chuangke.common.constant.Masks;
import com.chuangke.common.constant.SysBillConstants;
import com.chuangke.common.db.page.CkPageQuery;
import com.chuangke.common.enums.OrderStatusEnum;
import com.chuangke.common.exception.ChuangkeException;
import com.chuangke.common.idgen.IdManager;
import com.chuangke.common.trans.annotation.TransResult;
import com.chuangke.common.utils.DateUtils;
import com.chuangke.common.utils.SecurityUtils;
import com.chuangke.common.utils.WorkbookUtils;
import com.chuangke.context.service.ContextService;
import com.chuangke.flow.domain.FlowFormModel;
import com.chuangke.flow.service.FlowInstanceService;
import com.chuangke.mds.dao.MaterialAttributeConfDao;
import com.chuangke.mds.dao.MaterialAttributeValueDao;
import com.chuangke.mds.dao.MaterialDao;
import com.chuangke.mds.entity.Material;
import com.chuangke.mds.entity.MaterialAttributeConf;
import com.chuangke.mds.entity.MaterialAttributeValue;
import com.chuangke.mds.service.MaterialService;

import cn.hutool.core.util.StrUtil;

@Service
@Transactional(rollbackFor = Throwable.class)
public class MaterialServiceImpl implements MaterialService {

	@Autowired
	private MaterialDao materialDao;
	@Autowired
	private MaterialAttributeConfDao confDao;
	@Autowired
	private MaterialAttributeValueDao valueDao;
	@Autowired
	private FlowInstanceService flowInstanceService;
	@Autowired
	private ContextService contextService;

	@Override
	public String save(Material model) {
		return saveOrUpdate(model);
	}

	@Override
	public void update(Material model) {
		saveOrUpdate(model);
	}

	@Override
	public String saveOrUpdate(Material model) {
		if (StrUtil.isBlank(model.getId())) {
			doSave(model);
		} else {
			doUpdate(model);
		}
		return model.getId();
	}

	private void doSave(Material model) {
		model.setId(IdManager.nextId());
		model.setDeptId(contextService.getCurrentDeptId());
		model.setBisType(SysBillConstants.mds_material);
		model.setDate(DateUtils.getDate(new Date(), "yyyyMMdd"));
		model.setStatus(OrderStatusEnum.EDIT.getCode());
		
		materialDao.save(model);
		doSaveValueMap(model);
		doSaveValueList(model);

		FlowFormModel handler = new FlowFormModel();
		handler.setOrderId(model.getId());
		handler.setOrderType(model.getBisType());
		handler.setOrderDate(model.getDate());
		handler.setOrderRemarks(model.getRemarks());
		handler.setOrderCreatedAt(new Date());
		handler.setOrderCreatedBy(SecurityUtils.getUserId());
		handler.setOrderService(MaterialService.class.getName());
		handler.setOrderDeptId(model.getDeptId());

		Map<String, Object> variables = new HashMap<>();
		variables.put("bisType", model.getBisType());
		variables.put("deptId", model.getDeptId());
		handler.setVariables(variables);

		flowInstanceService.startInstanceByBillId(SysBillConstants.mds_material, Arrays.asList(handler));
	}

	private void doUpdate(Material model) {
		Material delay = materialDao.getOne(new QueryWrapper<Material>().lambda().eq(Material::getId, model.getId())) ;
		if(!OrderStatusEnum.EDIT.getCode().equals(delay.getStatus())) {
			throw new ChuangkeException("非编制状态，不允许编辑") ;
		}
		
		materialDao.updateById(model);

		valueDao.remove(new QueryWrapper<MaterialAttributeValue>().lambda().eq(MaterialAttributeValue::getMaterialId,
				model.getId()));
		doSaveValueMap(model);
		doSaveValueList(model);
	}

	private void doSaveValueMap(Material model) {
		Map<String, String> map = model.getAttributeValueMap();
		if (map != null && map.size() > 0) {
			List<MaterialAttributeValue> valueList = new ArrayList<>();
			for (Map.Entry<String, String> entry : model.getAttributeValueMap().entrySet()) {
				MaterialAttributeValue value = new MaterialAttributeValue();
				value.setId(IdManager.nextId());
				value.setMaterialId(model.getId());
				value.setStrV1(entry.getKey());
				value.setStrV2(entry.getValue());
				value.setAttributeType("hx");
				valueList.add(value);
			}
			valueDao.saveBatch(valueList);
		}
	}

	private void doSaveValueList(Material model) {
		List<MaterialAttributeValue> list = model.getAttributeValueList();
		list.forEach(value -> {
			value.setId(IdManager.nextId());
			value.setMaterialId(model.getId());
		});
		valueDao.saveBatch(list);
	}

	@Override
	public void delete(List<String> billIds) {
		QueryWrapper<Material> qw = new QueryWrapper<Material>();
		qw.lambda().in(Material::getId, billIds);
		List<Material> list = materialDao.list(qw) ;
		for(Material delay : list) {
			if(!OrderStatusEnum.EDIT.getCode().equals(delay.getStatus())) {
				throw new ChuangkeException("只能删除编制中的业务单据") ;
			}
		}

		materialDao.remove(new QueryWrapper<Material>().lambda().in(Material::getId, billIds));
		valueDao.remove(
				new QueryWrapper<MaterialAttributeValue>().lambda().in(MaterialAttributeValue::getMaterialId, billIds));
        flowInstanceService.deleteInstance(billIds);
	}

	@Override
	@TransResult
	public Material load(String billId) {
		Material material = materialDao.getOne(new QueryWrapper<Material>().lambda().eq(Material::getId, billId));
        if(material == null){
            throw new ChuangkeException("知识对应材料已被删除！");
        }
		// 化学成分的List
		List<MaterialAttributeValue> valueChemList = valueDao.list(new QueryWrapper<MaterialAttributeValue>().lambda()
				.eq(MaterialAttributeValue::getMaterialId, billId).eq(MaterialAttributeValue::getAttributeType, "hx"));
		Map<String, String> valueMap = valueChemList.stream().collect(HashMap::new,
				(m, v) -> m.put(v.getStrV1(), v.getStrV2()), HashMap::putAll);
		material.setAttributeValueMap(valueMap);
		// 非化学成分的List
		List<MaterialAttributeValue> valueOtherList = valueDao.list(new QueryWrapper<MaterialAttributeValue>().lambda()
				.eq(MaterialAttributeValue::getMaterialId, billId).ne(MaterialAttributeValue::getAttributeType, "hx"));
		material.setAttributeValueList(valueOtherList);
		List<String> confIdList = new ArrayList<>();
		valueOtherList.forEach(d -> {
			if (StrUtil.isNotBlank(d.getAttributeId())) {
				confIdList.add(d.getAttributeId());
			}
		});
		// 组织材料属性定义
		if (confIdList != null && !confIdList.isEmpty()) {
			List<MaterialAttributeConf> confList = confDao.list(
					new QueryWrapper<MaterialAttributeConf>().lambda().in(MaterialAttributeConf::getId, confIdList));
			material.setAttributeConfs(confList);
		}
		return material;
	}

	@Override
	@TransResult
	public IPage<Material> page(CkPageQuery page) {
		List<String> deptIds = contextService.getUserDataAndAuditDeptIdDetail() ;
		if(CollectionUtils.isEmpty(deptIds)) {
			return page.getPage() ; 
		}
		
		QueryWrapper<Material> qw = new QueryWrapper<>();
		if (!StringUtils.isEmpty(page.getAsString("name"))) {
			if ("code".equals(page.getAsString("filterSelection"))){
				qw.lambda().like(Material::getCode, page.getAsString("name"));
			}else if ("name".equals(page.getAsString("filterSelection"))){
				qw.lambda().like(Material::getName, page.getAsString("name"));
			}else if ("status".equals(page.getAsString("filterSelection"))){
				qw.lambda().eq(Material::getStatus, page.getAsString("name"));
			} else if ("remark".equals(page.getAsString("filterSelection"))) {
				qw.lambda().like(Material::getRemarks, page.getAsString("name"));
			}
		}
		
		qw.lambda().in(Material::getDeptId, deptIds) ;
//		SysUser user= contextService.getCurrentUser();
//		String userId = user.getId();
//		if (!"admin".equals(userId)) {
//			qw.lambda().eq(Material::getCreatedBy, userId);
//		}
		qw.lambda().orderByDesc(Material::getCreatedAt);
		return materialDao.page(page.getPage(), qw);
	}
	@Override
	@TransResult
	public List<Material> getList() {
		QueryWrapper<Material> qw = new QueryWrapper<>();
		qw.lambda().eq(Material::getStatus, "9") ;
		return materialDao.list(qw);
	}

    @Override
    public List<MaterialAttributeValue> importData(MultipartFile file) {
		Workbook workbook = WorkbookUtils.getWorkBook(file);
		Sheet sheetAt = workbook.getSheetAt(0);
		List<MaterialAttributeValue> resultList= new ArrayList<>();
		int rowNum=sheetAt.getLastRowNum();
		for(int rowIndex=1;rowIndex<=rowNum;rowIndex++){
			MaterialAttributeValue attributeValue=new MaterialAttributeValue();
			for(int k=0; k < sheetAt.getRow(rowIndex).getLastCellNum(); k++){//列名
				Cell cell = sheetAt.getRow(rowIndex).getCell(k);
				String value = WorkbookUtils.getValue(cell);
				if(k==0){
					attributeValue.setAttributeId(value);
				}else if(k==1){
					attributeValue.setStrV2(value);
				}
			}
			resultList.add(attributeValue);
		}

		return resultList;
    }

    @Override
	public void submitBatch(List<String> orderIdList) {
    	UpdateWrapper<Material> uw = new UpdateWrapper<>();
		uw.set(ColumnConstants.COL_STATUS, OrderStatusEnum.APPROVAL.getCode());
		uw.in("id", orderIdList).eq(ColumnConstants.COL_STATUS, OrderStatusEnum.EDIT.getCode());
		materialDao.update(uw);
	}

	@Override
	public void cancelSubmitBatch(List<String> orderIdList) {
		UpdateWrapper<Material> uw = new UpdateWrapper<>();
		uw.set(ColumnConstants.COL_STATUS, OrderStatusEnum.EDIT.getCode());
		uw.in("id", orderIdList).eq(ColumnConstants.COL_STATUS, OrderStatusEnum.APPROVAL.getCode());
		materialDao.update(uw);
	}

	@Override
	public void rejectBatch(List<String> orderIdList) {
		UpdateWrapper<Material> uw = new UpdateWrapper<>();
		uw.set(ColumnConstants.COL_STATUS, OrderStatusEnum.EDIT.getCode());
		uw.in("id", orderIdList).eq(ColumnConstants.COL_STATUS, OrderStatusEnum.APPROVAL.getCode());
		materialDao.update(uw);
	}

	@Override
	public void completeBatch(List<String> orderIdList) {
		UpdateWrapper<Material> uw = new UpdateWrapper<>();
		uw.set(ColumnConstants.COL_STATUS, OrderStatusEnum.COMPLETE.getCode());
		uw.in("id", orderIdList).eq(ColumnConstants.COL_STATUS, OrderStatusEnum.APPROVAL.getCode());
		materialDao.update(uw);
	}
	
	@Override
	public void knowleadged(String id) {
		UpdateWrapper<Material> uw = new UpdateWrapper<>();
		uw.lambda().set(Material::getKnowledged, Masks.BOOL_YES) ;
		uw.eq("id", id);
		materialDao.update(uw);
	}

	@Override
	public List<Material> getHomePageData(CkPageQuery page) {
		QueryWrapper<Material> qw = new QueryWrapper<>();
		qw.lambda().eq(Material::getStatus, OrderStatusEnum.COMPLETE.getCode()) ;
		qw.lambda().orderByDesc(Material::getCreatedAt);
		List<Material> list = materialDao.list(qw);
		return list.stream().limit(10).collect(Collectors.toList());
	}

}
